/* This is the updated version */
/* TODO: Generate more transfer rules.
 * DONE: Fixed training.
 */
package org.dlsu.hyfilengmt;

import java.io.PrintWriter;
import java.sql.Connection;
import java.sql.DriverManager;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.Statement;
import java.util.ArrayList;
import java.util.Enumeration;
import java.util.HashSet;
import java.util.Hashtable;
import java.util.StringTokenizer;
import java.util.Vector;

import leftMain.AnalysisModule;
import leftMain.GenerationModule;
import leftMain.LEFTTranslator;
import leftMain.LeftGUI;
import leftMain.Scanner;

import org.dlsu.mt.parser.FStructure;
import org.dlsu.mt.parser.FStructureElement;
import org.dlsu.mt.parser.FStructureElementString;
import org.dlsu.mt.parser.FStructureInterface;
import org.dlsu.mt.parser.FStructureSemantics;

import com.sun.corba.se.spi.ior.MakeImmutable;

import text.ia.InputAnalyzer;
import text.ia.TExtLexicon;
import text.obj.AlignedSentence;

/**
 * The main class of org.dlsu.hyfilengmt.
 *
 * @author pckid
 */
public class Tester {

	public static LeftGUI gui;
	static FStructureInterface fsRule, fsParent;
	// if the maximum compositional rule for both languages has already been
	// generated
	static boolean parentFound, fsFound, maxCompReached;
	public static Vector vFilUnion, vEngUnion;
	static Vector transferRuleList[];
	static Vector transferRuleSet;
	static int transferRuleIndex;
	static PrintWriter trainingOut;
	static PrintWriter translationOut;
	static Hashtable uRulesEng;
	static Hashtable uRulesFil;
	static int headCountGlobal;

	/**
	 * Commences the training phase. Calls analyzeCorpus().
	 *
	 * @param args
	 */
	public static void hybridTrain() {
		String strFilipinoCorpus = "Siya ay pumunta sa palengke.";
		String strEnglishCorpus = "He went to the market.";

		try {
			trainingOut = new PrintWriter("/home/pckid/LEFT/trainingOut.txt");
			trainingOut.println("TRAINING STARTED");
			trainingOut.println("Filipino Corpus: " + strFilipinoCorpus);
			trainingOut.println("English Corpus: " + strEnglishCorpus);
		} catch (Exception e) {
			System.out.println("Training error: " + e.getMessage());
		}

		System.out.println("\r\nTRAINING STARTED");

		boolean bFilipinoSource = true;
		// InputAnalysis
		InputAnalyzer ia = new InputAnalyzer();
		Vector vAlignedSentences = ia.analyzeTrainInput(strFilipinoCorpus,
				strEnglishCorpus, 'e', "Regular Expression");

		Hashtable alignedTokensFilSource[] = new Hashtable[vAlignedSentences
				.size()];
		Hashtable alignedTokensEngSource[] = new Hashtable[vAlignedSentences
				.size()];

		// get the alignment (aligned tokens)
		// Filipino tokens are the keys while English tokens are the elements
		for (int i = 0; i < vAlignedSentences.size(); i++) {
			alignedTokensFilSource[i] = ((AlignedSentence) vAlignedSentences
					.elementAt(i)).getAlignment();
		}

		// English tokens are the keys while Filipino tokens are the elements
		vAlignedSentences = ia.analyzeTrainInput(strEnglishCorpus,
				strFilipinoCorpus, 'f', "Regular Expression");
		for (int i = 0; i < vAlignedSentences.size(); i++) {
			alignedTokensEngSource[i] = ((AlignedSentence) vAlignedSentences
					.elementAt(i)).getAlignment();
		}

		// arrangeTokens(alignedTokensFilSource, alignedTokensEngSource);
		try {
			analyzeCorpus(strFilipinoCorpus, strEnglishCorpus,
					alignedTokensFilSource, alignedTokensEngSource);
			trainingOut.println("\r\nTRAINING FINISHED");
			trainingOut.close();
		} catch (Exception e) {
			System.out.println("ERROR is " + e.getLocalizedMessage());
			e.printStackTrace();
		}
		System.out.println("TRAINING FINISHED");
	}

	/**
	 * Analyzes the parallel corpus. Calls generateTransferRules().
	 *
	 * @param strFilipinoCorpus
	 *            The Filipino corpus
	 * @param strEnglishCorpus
	 *            The English corpus
	 * @param alignedTokensFilSource
	 *            The list of aligned tokens generated when Filipino is used as
	 *            the reference in matching
	 * @param alignedTokensEngSource
	 *            The list of aligned tokens generated when English is used as
	 *            the reference in matching
	 */
	public static void analyzeCorpus(String strFilipinoCorpus,
			String strEnglishCorpus, Hashtable alignedTokensFilSource[],
			Hashtable alignedTokensEngSource[]) throws Exception {

		PrintWriter writer = new PrintWriter("/home/pckid/LEFT/LOG2.txt");
		LEFTTranslator translator = new LEFTTranslator(writer);
		PrintWriter outWriter = new PrintWriter(
				"/home/pckid/LEFT/training_output.txt");

		Scanner scannerFilipino = new Scanner();
		Scanner scannerEnglish = new Scanner();
		FStructure fsFilipino[] = null; // the array of Filipino f-structures
		// from the corpus
		FStructure fsEnglish[] = null; // the array of English f-structures from
		// the corpus
		org.dlsu.mt.parser.dictionary.Dictionary language2Dictionary = new org.dlsu.mt.parser.dictionary.Dictionary(
				"Language2");
		org.dlsu.mt.parser.dictionary.Dictionary language1Dictionary = new org.dlsu.mt.parser.dictionary.Dictionary(
				"Language1");
		AnalysisModule analysis = new AnalysisModule();
		GenerationModule gen = new GenerationModule();
		int numFilTokensBasic = 0, numEngTokensBasic = 0;

		// f = analysis.analyze(text+" $");
		int l = 0;

		try {
			scannerFilipino.cLang = '2';
			scannerFilipino.scanNoGUI(strFilipinoCorpus, translator);
			// analysis.setGrammar("c:/language2.txt");
			analysis.reload("/home/pckid/LEFT/language2.txt",
					language2Dictionary);
			// analysis.init();
			// gen.loadGrammar("c:/language1.txt");
			fsFilipino = new FStructure[scannerFilipino.sentences.size()];
			while (l < scannerFilipino.sentences.size()) {
				// System.out.println("Enter while");
				if (scannerFilipino.acceptedSentences.get(l) == true) {
					// outWriter.append(translator.translate1To2(scanner.sentences.get(l).toString())
					// + scanner.punctuation.get(l));

					fsFilipino[l] = analysis
							.analyzeFilipino(scannerFilipino.sentences.get(l)
									.toString()
									+ " $");
					// System.out.println("sentence accepted2");
					if (fsFilipino[l] != null)
						System.out.println("Analysis successful");

					StringTokenizer tokenizer = new StringTokenizer(
							scannerFilipino.sentences.get(l).toString());
					numFilTokensBasic = tokenizer.countTokens();
				}
				l++;
				if (l != scannerFilipino.sentences.size())
					outWriter.append(" ");
			}

			System.out.println("GIAN IS PRINTING THE CONTENTS");
			printFStructureContentsRecursive(fsFilipino[0], "\t");
			trainingOut.println("\r\nFilipino Parse Tree");
			printFStructureContentsRecursive(fsFilipino[0], "\t", trainingOut);

		} catch (Exception e) {
			outWriter.println("Error Analyzing Filipino Corpus using RBE");
		}

		l = 0;

		try {
			scannerEnglish.cLang = '1';
			scannerEnglish.scanNoGUI(strEnglishCorpus, translator);
			analysis.reload("/home/pckid/LEFT/language1.txt",
					language1Dictionary);
			fsEnglish = new FStructure[scannerEnglish.sentences.size()];

			while (l < scannerEnglish.sentences.size()) {
				if (scannerEnglish.acceptedSentences.get(l) == true) {
					// outWriter.append(translator.translate1To2(scanner.sentences.get(l).toString())
					// + scanner.punctuation.get(l));
					fsEnglish[l] = analysis
							.analyzeEnglish(scannerEnglish.sentences.get(l)
									.toString()
									+ " $");

					StringTokenizer tokenizer = new StringTokenizer(
							scannerEnglish.sentences.get(l).toString());
					numEngTokensBasic = tokenizer.countTokens();
				}
				l++;
				if (l != scannerEnglish.sentences.size())
					outWriter.append(" ");
			}

			System.out.println("GIAN IS PRINTING THE CONTENTS");
			printFStructureContentsRecursive(fsEnglish[0], "\t");

			trainingOut.println("\r\nEnglish Parse Tree");
			printFStructureContentsRecursive(fsEnglish[0], "\t", trainingOut);

		} catch (Exception e) {
			outWriter.println("Error Analyzing English Corpus using RBE");
		}

		if (scannerFilipino.sentences.size() == scannerEnglish.sentences.size()) {

			// After deriving the f-structures for both English and Filipino,
			// generate transfer rules using alignment stored in alignedTokens
			generateTransferRules(fsFilipino, fsEnglish,
					alignedTokensFilSource, alignedTokensEngSource);
		} else
			System.out
					.println("Filipino and English sentences don't match! No transfer rules generated!");
		// close the log files
		writer.close();

	}

	/**
	 * Arranges the tokens (for testing only)
	 *
	 * @param alignedTokensFilSource
	 *            The list of aligned tokens generated when Filipino is used as
	 *            the reference in matching
	 * @param alignedTokensEngSource
	 *            The list of aligned tokens generated when English is used as
	 *            the reference in matching
	 */
	public static void arrangeTokens(Hashtable alignedTokensFilSource[],
			Hashtable alignedTokensEngSource[]) {
		// Filipino - English
		for (int i = 0; i < alignedTokensFilSource.length; i++) {
			Enumeration filKeys = alignedTokensFilSource[i].keys();
			Enumeration engKeys = alignedTokensEngSource[i].keys();

			filKeys = alignedTokensFilSource[i].keys();
			engKeys = alignedTokensEngSource[i].keys();
			Vector vFilTokensTemp1 = new Vector(), vEngTokensTemp1 = new Vector();
			Vector vFilTokensTemp2 = new Vector(), vEngTokensTemp2 = new Vector();
			Vector vFilTokens = new Vector(), vEngTokens = new Vector();

			{
				// System.out.println("here1");
				Enumeration keys = filKeys;
				// Enumeration engTokens =
				// alignedTokens[i].elements().toString().trim();

				// expand the token list if there exists an alignment like: <ang
				// = the, the>, create two instances of: <ang = the>
				while (keys.hasMoreElements()) {
					Object tempFilToken = keys.nextElement();
					Object tempEngToken = trimElement(alignedTokensFilSource[i]
							.get(tempFilToken));

					StringTokenizer tokenizer = new StringTokenizer(
							tempEngToken.toString(), ",");
					if (tokenizer.countTokens() > 1) {
						while (tokenizer.hasMoreTokens()) {
							vFilTokensTemp1.addElement(tempFilToken.toString()
									.trim());
							vEngTokensTemp1.addElement(tokenizer.nextToken()
									.trim());
						}
					} else {
						vFilTokensTemp1.addElement(tempFilToken.toString()
								.trim());
						vEngTokensTemp1.addElement(tempEngToken.toString()
								.trim());
					}
				}
			}

			{
				Enumeration keys = engKeys;
				// System.out.println("here2");

				// Enumeration engTokens =
				// alignedTokens[i].elements().toString().trim();

				// expand the token list if there exists an alignment like: <the
				// = ang, ang>, create two instances of: <the = ang>
				while (keys.hasMoreElements()) {
					Object tempEngToken = keys.nextElement();
					Object tempFilToken = trimElement(alignedTokensEngSource[i]
							.get(tempEngToken));

					StringTokenizer tokenizer = new StringTokenizer(
							tempFilToken.toString(), ",");
					if (tokenizer.countTokens() > 1) {
						while (tokenizer.hasMoreTokens()) {
							vFilTokensTemp2.addElement(tokenizer.nextToken()
									.trim());
							vEngTokensTemp2.addElement(tempEngToken.toString()
									.trim());
						}
					} else {
						vFilTokensTemp2.addElement(tempFilToken.toString()
								.trim());
						vEngTokensTemp2.addElement(tempEngToken.toString()
								.trim());
					}
				}
			}

			unionTokens(vFilTokensTemp1, vEngTokensTemp1, vFilTokensTemp2,
					vEngTokensTemp2);
			vFilTokens = vFilUnion;
			vEngTokens = vEngUnion;

			vFilUnion = null;
			vEngUnion = null;

			for (int j = 0; j < vFilTokens.size(); j++) {
				System.out.print(vFilTokens.elementAt(j));
				System.out.print(" = " + vEngTokens.elementAt(j));
				System.out.print(", ");
			}
			System.out.println();
		}
	}

	/**
	 * Checks if a certain word alignment already exists.
	 *
	 * @param vFilTokens
	 *            The list of Filipino tokens
	 * @param vEngTokens
	 *            The list of English tokens
	 * @param filToken
	 *            The Filipino token in the alignment
	 * @param engToken
	 *            The English token in the alignment
	 * @return rue if a certain alignment already exists
	 */
	public static boolean checkIfAlignmentExists(Vector vFilTokens,
			Vector vEngTokens, String filToken, String engToken) {

		for (int i = 0; i < vFilTokens.size(); i++) {
			if (vFilTokens.elementAt(i).equals(filToken)
					&& vEngTokens.elementAt(i).equals(engToken)) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Generates the transfer rules based on the c-structures of the source and
	 * the target language and the alignment. Calls popFE().
	 *
	 * @param fsFilipino
	 *            The generated f-structure of the Filipino sentence
	 * @param fsEnglish
	 *            The generated f-structure of the English sentence
	 * @param filToken
	 *            The Filipino token in the alignment
	 * @param engToken
	 *            The English token in the alignment
	 * @return void
	 */
	public static void generateTransferRules(FStructure fsFilipino[],
			FStructure fsEnglish[], Hashtable alignedTokensFilSource[],
			Hashtable alignedTokensEngSource[]) {

		FStructureInterface filFSRule = null;
		FStructureInterface engFSRule = null;

		transferRuleList = new Vector[alignedTokensFilSource.length];

		// Filipino - English
		for (int i = 0; i < alignedTokensFilSource.length; i++) {
			Enumeration filKeys = alignedTokensFilSource[i].keys();
			Enumeration engKeys = alignedTokensEngSource[i].keys();

			filKeys = alignedTokensFilSource[i].keys();
			engKeys = alignedTokensEngSource[i].keys();
			Vector vFilTokensTemp1 = new Vector(), vEngTokensTemp1 = new Vector();
			Vector vFilTokensTemp2 = new Vector(), vEngTokensTemp2 = new Vector();
			Vector vFilTokens = new Vector(), vEngTokens = new Vector();

			{
				// System.out.println("here1");
				Enumeration keys = filKeys;
				// Enumeration engTokens =
				// alignedTokens[i].elements().toString().trim();

				// expand the token list if there exists an alignment like: <ang
				// = the, the>, create two instances of: <ang = the>
				while (keys.hasMoreElements()) {
					Object tempFilToken = keys.nextElement();
					Object tempEngToken = trimElement(alignedTokensFilSource[i]
							.get(tempFilToken));

					StringTokenizer tokenizer = new StringTokenizer(
							tempEngToken.toString(), ",");
					if (tokenizer.countTokens() > 1) {
						while (tokenizer.hasMoreTokens()) {
							vFilTokensTemp1.addElement(tempFilToken.toString()
									.trim());
							vEngTokensTemp1.addElement(tokenizer.nextToken()
									.trim());
						}
					} else {
						vFilTokensTemp1.addElement(tempFilToken.toString()
								.trim());
						vEngTokensTemp1.addElement(tempEngToken.toString()
								.trim());
					}
				}
			}

			{
				Enumeration keys = engKeys;
				// System.out.println("here2");

				// Enumeration engTokens =
				// alignedTokens[i].elements().toString().trim();

				// expand the token list if there exists an alignment like: <the
				// = ang, ang>, create two instances of: <the = ang>
				while (keys.hasMoreElements()) {
					Object tempEngToken = keys.nextElement();
					Object tempFilToken = trimElement(alignedTokensEngSource[i]
							.get(tempEngToken));

					StringTokenizer tokenizer = new StringTokenizer(
							tempFilToken.toString(), ",");
					if (tokenizer.countTokens() > 1) {
						while (tokenizer.hasMoreTokens()) {
							vFilTokensTemp2.addElement(tokenizer.nextToken()
									.trim());
							vEngTokensTemp2.addElement(tempEngToken.toString()
									.trim());
						}
					} else {
						vFilTokensTemp2.addElement(tempFilToken.toString()
								.trim());
						vEngTokensTemp2.addElement(tempEngToken.toString()
								.trim());
					}
				}
			}

			unionTokens(vFilTokensTemp1, vEngTokensTemp1, vFilTokensTemp2,
					vEngTokensTemp2);
			vFilTokens = vFilUnion;
			vEngTokens = vEngUnion;

			// check if there is an alignment like [mga tao = people] or
			// [maglalaro = will play]
			// if there is, separate into [mga = null] and [tao = people]

			for (int j = 0; j < vFilTokens.size(); j++) {
				StringTokenizer tokenizerF = new StringTokenizer(
						(String) vFilTokens.elementAt(j), " ");
				StringTokenizer tokenizerE = new StringTokenizer(
						(String) vEngTokens.elementAt(j), " ");

				String filToken = (String) vFilTokens.elementAt(j);
				String engToken = (String) vEngTokens.elementAt(j);

				if (tokenizerF.countTokens() > 1) {
					vFilTokens.removeElementAt(j);
					vEngTokens.removeElementAt(j);
					vFilTokens.add(tokenizerF.nextToken().trim());
					vEngTokens.add("null");
					vFilTokens.add(tokenizerF.nextToken().trim());
					vEngTokens.add(engToken);
				} else if (tokenizerE.countTokens() > 1) {
					vEngTokens.removeElementAt(j);
					vFilTokens.removeElementAt(j);
					vEngTokens.add(tokenizerE.nextToken().trim());
					vFilTokens.add("null");
					vEngTokens.add(tokenizerE.nextToken().trim());
					vFilTokens.add(filToken);
				}
			}

			vFilUnion = null;
			vEngUnion = null;

			for (int j = 0; j < vFilTokens.size(); j++) {
				System.out.print(vFilTokens.elementAt(j));
				System.out.print(" = " + vEngTokens.elementAt(j));
				System.out.print(", ");
			}
			System.out.println();

			try {
				System.out.println("Transfer rules for sentence number " + i);
				transferRuleSet = new Vector(); // all transfer rules belonging
				// to this current example will
				// be stored here
				boolean analysisError = false;
				// if no f-structure was created for either English or Filipino
				// in this example
				if (fsFilipino[i] == null || fsEnglish[i] == null) {
					analysisError = true;
					System.out
							.println("Error during analysis, no fstructure created "
									+ i);
				}

				String ruleSet = new String("00" + System.currentTimeMillis());
				maxCompReached = false;

				for (int j = 0; (j < vFilTokens.size() && !analysisError && !maxCompReached); j++) {
					Object filToken = vFilTokens.elementAt(j);
					Object engToken = vEngTokens.elementAt(j);

					System.out.println("FilToken: " + filToken + " "
							+ "EngToken: " + engToken);
					filFSRule = null;
					engFSRule = null;
					fsRule = null;

					if (!filToken.toString().equalsIgnoreCase("null")
							&& !filToken.toString().equalsIgnoreCase(".")) {

						// fsFilipino[i].fePopped = true;
						fsFound = false;
						searchFStructure(fsFilipino[i], filToken, "fe");
						filFSRule = fsRule;
						fsRule = null;

						// System.out.println("For filFSRule " +
						// filFSRule.getName());
						/*
						 * parentFound = false; getFSParent(fsFilipino[i],
						 * filFSRule); System.out.println("Token is " + filToken
						 * + " filFSrule is " + filFSRule.getName() +
						 * " parent is " + fsParent.getName());
						 */
					}

					if (!engToken.toString().equalsIgnoreCase("null")
							&& !engToken.toString().equalsIgnoreCase(".")) {

						// fsEnglish[i].fePopped = true;
						fsFound = false;
						searchFStructure(fsEnglish[i], engToken, "fe");
						engFSRule = fsRule;
						fsRule = null;

						/*
						 * parentFound = false; getFSParent(fsEnglish[i],
						 * engFSRule); System.out.println("Token is " + engToken
						 * + " engFSrule is " + engFSRule.getName() +
						 * " parent is " + fsParent.getName());
						 */
					}

					if (filFSRule != null
							|| engFSRule != null
							&& (filToken.toString().equalsIgnoreCase("null") || engToken
									.toString().equalsIgnoreCase("null"))) {

						String tempFilSide = new String(), tempEngSide = new String();
						// these are the seed rules
						if (filFSRule != null) {
							// parentFound = false;
							// getFSParent(fsFilipino[i], filFSRule);
							System.out.println("Fil side= "
									+ filFSRule.getName() /*
														 * + " parent is " +
														 * fsParent.toString()
														 */);
							tempFilSide = filFSRule.getName();
						} else {
							System.out.println("Fil side= null");
							tempFilSide = "null";
						}
						if (engFSRule != null) {
							// parentFound = false;
							// getFSParent(fsEnglish[i], engFSRule);
							System.out.println("Eng side= "
									+ engFSRule.getName() /*
														 * + " parent is " +
														 * fsParent.toString()
														 */);
							tempEngSide = engFSRule.getName();
						} else {
							System.out.println("Eng side= null");
							tempEngSide = "null";
						}

						transferRuleSet.add(new TransferRule(tempFilSide,
								tempEngSide, ruleSet));
						System.out.println();

						popFE(filFSRule, engFSRule, fsFilipino[i],
								fsEnglish[i], ruleSet); // generate compound
						// rules
					}
				}

				transferRuleList[i] = transferRuleSet;
			} catch (Exception e) {
				System.out
						.println("Error generating transfer rule for sentence number "
								+ i + " due to improper alignment!");
				System.out.println(e.getMessage());
				// e.printStackTrace();
			}
		}

		for (int i = 0; i < transferRuleList.length; i++) {
			System.out.println("Transfer Rule Set " + i);
			trainingOut.println("\r\nTransfer Rule Set " + i);
			for (int j = 0; j < transferRuleList[i].size(); j++) {
				((TransferRule) transferRuleList[i].elementAt(j))
						.printTransferRule(trainingOut);
				((TransferRule) transferRuleList[i].elementAt(j))
						.printTransferRule();
				//((TransferRule)transferRuleList[i].elementAt(j)).addRuleToDB();
			}
		}
		// English - Filipino
	}

	/**
	 * Loads the transfer rules of a given rule set given the ruleSet
	 * identifier.
	 *
	 * @param ruleSet
	 *            The identifier of the rule set to be loaded
	 * @return The TransferRule object referred to by ruleSet queried from the
	 *         database
	 */
	public static Vector<TransferRule> loadTransferRuleSet(String ruleSet) {
		String query = new String();
		Vector<TransferRule> vTransferRuleSet = new Vector();
		try {
			Class.forName("com.mysql.jdbc.Driver");
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/leftDB", "root", "");
			Statement stmt = con.createStatement();

			query = "SELECT filSide, engSide FROM hybridTransferRules WHERE ruleSet = '"
					+ ruleSet + "'";
			System.out.println("QUERY is " + query);

			ResultSet rs = stmt.executeQuery(query);

			String filSide = null, engSide = null;

			while (rs.next()) {
				filSide = rs.getString("filSide");
				engSide = rs.getString("engSide");
				vTransferRuleSet
						.add(new TransferRule(filSide, engSide, ruleSet));
			}

			if (rs != null) {
				rs.close();

				con.close();
				return vTransferRuleSet;
			}

			con.close();
			return null;
		} catch (Exception e) {
			System.out.println("Connection to database failed!");
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Gets the union of the two token sets: 1) Filipino as reference point 2)
	 * English as reference point.
	 *
	 * @param vFilTokensTemp1
	 * @param vEngTokensTemp1
	 * @param vFilTokensTemp2
	 * @param vEngTokensTemp2
	 */
	public static void unionTokens(Vector vFilTokensTemp1,
			Vector vEngTokensTemp1, Vector vFilTokensTemp2,
			Vector vEngTokensTemp2) {
		vFilUnion = new Vector();
		vEngUnion = new Vector();
		boolean bFound = false;
		int i = 0;

		while (i < vFilTokensTemp1.size()) {
			bFound = false;
			// System.out.print("Token " + vFilTokensTemp1.elementAt(i) + " = "
			// + vEngTokensTemp1.elementAt(i));
			for (int j = 0; j < vFilTokensTemp2.size(); j++) {
				if (vFilTokensTemp1.elementAt(i).equals(
						vFilTokensTemp2.elementAt(j))
						&& vEngTokensTemp1.elementAt(i).equals(
								vEngTokensTemp2.elementAt(j))) {
					vFilUnion.add(0, vFilTokensTemp1.elementAt(i));
					vEngUnion.add(0, vEngTokensTemp1.elementAt(i));
					vFilTokensTemp1.remove(i);
					vFilTokensTemp2.remove(j);
					vEngTokensTemp1.remove(i);
					vEngTokensTemp2.remove(j);
					bFound = true;
					i = 0;
					// System.out.println(" Token found!");
				}
			}

			if (bFound == false) { // System.out.println(" Token not found");
				i++;
			}
		}

		// add the remaining elements in temp1 that were not found in temp2
		for (i = 0; i < vFilTokensTemp1.size(); i++) {
			vFilUnion.add(0, vFilTokensTemp1.elementAt(i));
			vEngUnion.add(0, vEngTokensTemp1.elementAt(i));
		}

		// if there are remaining elements found in temp2 (did not match to an
		// element in temp1)
		for (int j = 0; j < vFilTokensTemp2.size(); j++) {
			vFilUnion.add(0, vFilTokensTemp2.elementAt(j));
			vEngUnion.add(0, vEngTokensTemp2.elementAt(j));
		}
	}

	/**
	 * Removes unnecessary characters from Element
	 *
	 * @param o
	 *            The Object to be trimmed
	 * @return The trimmed element Object
	 */
	public static Object trimElement(Object o) {
		String s = o.toString();
		s = s.replace('[', ' ');
		s = s.replace(']', ' ');
		s = s.trim();
		return s;
	}

	/**
	 * Returns the child f-structure of a parent fsParent, given the name of the
	 * child f-structure.
	 *
	 * @param fParent
	 *            The parent f-structure
	 * @param fsName
	 *            The string name of the child f-structure to be returned
	 * @return The child f-structure itself as a FStructureInterface object
	 */
	public static FStructureInterface getChildFStruct(FStructure fParent,
			String fsName) {
		Enumeration e = fParent.values.keys();
		FStructureInterface f = null;

		while (e.hasMoreElements()) {
			String key = (String) e.nextElement();
			f = (FStructureInterface) fParent.values.get(key);
			if (f.getName().equals(fsName)) {
				return f;
			}
		}

		return null;
	}

	/**
	 * Sequentially pops from f-struct to highest ancestor f-struct possbile;
	 * this generates the compound rules.
	 *
	 * @param filFSRule
	 *            The current Filipino f-structure node
	 * @param engFSRule
	 *            The current English f-structure node
	 * @param filRoot
	 *            The root node of the Filipino tree
	 * @param engRoot
	 *            The root node of the English tree
	 * @param ruleSet
	 *            A string identifying the rule set that the generated rules
	 *            will belong to
	 */
	public static void popFE(FStructureInterface filFSRule,
			FStructureInterface engFSRule, FStructure filRoot,
			FStructure engRoot, String ruleSet) {

		FStructureInterface filFSRuleCurr = filFSRule, engFSRuleCurr = engFSRule;
		FStructureInterface filParent = null, engParent = null;
		boolean hasPopped = true;
		boolean hasPoppedF = false, hasPoppedE = false;
		FStructureInterface tempTest = null;

		while (hasPopped) {
			hasPopped = false;
			hasPoppedF = false;
			hasPoppedE = false;

			if (filFSRuleCurr != null
					&& !filFSRuleCurr.getName().equalsIgnoreCase("root")) {
				parentFound = false;
				getFSParent(filRoot, filFSRuleCurr);
				filParent = fsParent;
				hasPoppedF = false;
				if (filParent != null && filParent instanceof FStructure
						&& !((FStructure) filParent).fePopped) {
					// check if all elements of this FStructure have popped
					// already

					if (checkIfElementsPoppedFE((FStructure) filParent)) {
						((FStructure) filParent).fePopped = true;
						filFSRuleCurr = filParent;
						hasPoppedF = true;
					}

				} else if (filParent != null
						&& filParent instanceof FStructureElement
						&& !((FStructure) filParent).fePopped) {
					if (checkIfElementsPoppedFE((FStructure) filParent)) {
						((FStructureElement) filParent).fePopped = true;
						filFSRuleCurr = filParent;
						hasPoppedF = true;
					}
				}
			}

			if (engFSRuleCurr != null
					&& !engFSRuleCurr.getName().equalsIgnoreCase("root")) {
				parentFound = false;
				getFSParent(engRoot, engFSRuleCurr);
				engParent = fsParent;
				hasPoppedE = false;
				if (engParent != null && engParent instanceof FStructure
						&& !((FStructure) engParent).fePopped) {
					if (checkIfElementsPoppedFE((FStructure) engParent)) {
						((FStructure) engParent).fePopped = true;
						engFSRuleCurr = engParent;
						hasPoppedE = true;
					}
				} else if (engParent != null
						&& engParent instanceof FStructureElement
						&& !((FStructure) engParent).fePopped) {
					if (checkIfElementsPoppedFE((FStructure) engParent)) {
						((FStructureElement) engParent).fePopped = true;
						engFSRuleCurr = engParent;
						hasPoppedE = true;
					}
				}
			}
			// this block might need to be outside of
			// "if (engFSRuleCurr!=null && !engFSRuleCurr.getName().equalsIgnoreCase("root")) "
			String tempFilSide = new String(), tempEngSide = new String();
			if (!hasPoppedF && !hasPoppedE) {
				hasPopped = false;
			} else if (hasPoppedF && hasPoppedE) {
				hasPopped = true;
				System.out.println("Fil side= " + filParent.getName()
						+ " : " + getChildren((FStructure) filParent));
				System.out.println("Eng side= " + engParent.getName()
						+ " : " + getChildren((FStructure) engParent));
				System.out.println();
				tempFilSide = filParent.getName() + " : "
				+ getChildren((FStructure) filParent);
				tempEngSide = engParent.getName() + " : "
				+ getChildren((FStructure) engParent);

				if (engParent.getName().equalsIgnoreCase("SUBJ")) {
					if (checkPlurality((FStructure) engParent, 0)) {
						((FStructure) engParent).setPlurality("plur");
					}
				}
				if (filParent.getName().equalsIgnoreCase("SUBJ")) {
					if (checkPlurality((FStructure) filParent, 0)) {
						((FStructure) filParent).setPlurality("plur");
					}
					System.out.println("FilParent = "
							+ filParent.toString());
				}
				if (filParent.getName().equalsIgnoreCase("root")
						&& engParent.getName().equals("root")) {
					maxCompReached = true;
					System.out.println("Max comp reached 1");
					if (getChildren((FStructure) engParent)
							.contains("SUBJ")
							&& getChildren((FStructure) engParent)
							.contains("aux")) {

						// add unification constraint here
						// check SUBJ and aux agreement
						// check SUBJ and verb agreement
						FStructureInterface fSUBJ, fAux;
						fSUBJ = getChildFStruct((FStructure) engParent,
						"SUBJ");
						fAux = getChildFStruct((FStructure) engParent,
						"aux");

						if (checkPlurality((FStructureElement) fAux)) {
							((FStructureElement) fAux).setPlurality("plur");
						}

						if (((FStructureElement) fAux)
								.getPlurality()
								.equalsIgnoreCase(
										((FStructure) fSUBJ).getPlurality())) {
							// new unification constraint

							System.out
							.println("Unif constraint= eng:aux:num = eng:SUBJ:num");
						}
					}
				}

				transferRuleSet.add(new TransferRule(tempFilSide,
						tempEngSide, ruleSet));
			} else if (hasPoppedF && !hasPoppedE) {
				hasPopped = true;
				System.out.println("Fil side= " + filParent.getName()
						+ " : " + getChildren((FStructure) filParent));
				tempFilSide = filParent.getName() + " : "
				+ getChildren((FStructure) filParent);
				// System.out.println("Eng side= null");
				if (engFSRuleCurr instanceof FStructure) {
					System.out.println("Eng side= "
							+ engFSRuleCurr.getName() + " : "
							+ getChildren((FStructure) engFSRuleCurr));
					tempEngSide = engFSRuleCurr.getName() + " : "
					+ getChildren((FStructure) engFSRuleCurr);
				} else if(engFSRuleCurr != null){
					System.out.println("Eng side= "
							+ engFSRuleCurr.getName());
					tempEngSide = engFSRuleCurr.getName();
					// hasPopped = false;
				}
				else {
					System.out.println("Eng side= "	+ "null");
					tempEngSide = "null";
				}
				System.out.println();

				if (filParent.getName().equalsIgnoreCase("SUBJ")) {
					if (checkPlurality((FStructure) filParent, 0)) {
						((FStructure) filParent).setPlurality("plur");
					}
				}
				if (filParent.getName().equalsIgnoreCase("root")
						&& engFSRuleCurr.getName().equals("root")) {
					maxCompReached = true;
					System.out.println("Max comp reached 2");
				}
				transferRuleSet.add(new TransferRule(tempFilSide,
						tempEngSide, ruleSet));
			} else if (!hasPoppedF && hasPoppedE) {
				hasPopped = true;
				if (filFSRuleCurr instanceof FStructure) {
					System.out.println("Fil side= "
							+ filFSRuleCurr.getName() + " : "
							+ getChildren((FStructure) filFSRuleCurr));
					tempFilSide = filFSRuleCurr.getName() + " : "
					+ getChildren((FStructure) filFSRuleCurr);
				} else if (filFSRuleCurr != null){
					System.out.println("Fil side= "
							+ filFSRuleCurr.getName());
					tempFilSide = filFSRuleCurr.getName();
				}
				else {
					System.out.println("Fil side= "	+ "null");
					tempFilSide = "null";
				}
				// System.out.println("Fil side= null");

				/*
				 * Check if the comp rule is the SUBJ constituent if it is,
				 * check if the SUBJ has plural children nodes or if it has
				 * multiple HEAD constituents if yes, then this SUBJ
				 * constituent should also be plural
				 */

				System.out.println("Eng side= " + engParent.getName()
						+ " : " + getChildren((FStructure) engParent));
				tempEngSide = engParent.getName() + " : "
				+ getChildren((FStructure) engParent);
				System.out.println();

				if (engParent.getName().equalsIgnoreCase("SUBJ")) {
					if (checkPlurality((FStructure) engParent, 0)) {
						((FStructure) engParent).setPlurality("plur");
					}
				}

				if (filFSRuleCurr.getName().equalsIgnoreCase("root")
						&& engParent.getName().equals("root")) {
					maxCompReached = true;
					System.out.println("Max comp reached 3");
				}
				transferRuleSet.add(new TransferRule(tempFilSide,
						tempEngSide, ruleSet));
				// end of block
			}
		}
	}

	/**
	 * Checks recursively whether this (SUBJ or Root) f-structure contains
	 * either a plural HEAD node or has 2 or more HEAD nodes. If so, then make
	 * this f-structure plural as well. This is part of the unification phase.
	 * Set headCountGlobal to 0 before first call to this method.
	 *
	 * @param fstruct
	 *            The f-structure to be checked
	 * @param headCount
	 *            Set the argument to this parameter to 0 when calling the
	 *            method (recursion control variable)
	 * @return True if this f-structure is plural via checking the HEAD node/s
	 */
	public static boolean checkPlurality(FStructure fstruct, int headCount) {
		String key;
		Enumeration e = fstruct.values.keys();
		FStructureInterface f = null;
		boolean isPlural = false;

		while (e.hasMoreElements() && !isPlural) {
			key = (String) e.nextElement();
			f = (FStructureInterface) fstruct.values.get(key);

			// System.out.print(tabIndent + "FS " + f.getName());
			if (f.getName().equalsIgnoreCase("SUBJ")) {
				// then this is plural
				// isPlural = true;
				System.out.println("CP SUBJ + headCountGlobal = "
						+ headCountGlobal);

				// fstruct.setPlurality("plur");
			} else if (f.getName().equalsIgnoreCase("HEAD")) {
				headCount++;
				headCountGlobal++;
				if (headCount > 1 || headCountGlobal > 1) {

					isPlural = true;
					System.out.println("AHOO pl");
					// fstruct.setPlurality("plur");
					return true;
				}
			}

			if (f instanceof FStructureElement) {
				String features[] = ((FStructureElement) f).getFeatures();
				for (int i = 0; i < features.length; i++) {
					if (features[i].equals("NUM=plur")) {

						// fstruct.setPlurality("plur");
						System.out.println("AHOO pl pl");
						return true;
					}
				}
			} else if (f instanceof FStructure && !isPlural) {
				// printFStructureContentsRecursive((FStructure)f, tabIndent +
				// "\t");
				if (((FStructure) f).getPlurality().equalsIgnoreCase("plur")) {
					// then this is plural
					// System.out.println("AHOO pl pl");
					// fstruct.setPlurality("plur");
					return true;
				} else {
					isPlural = checkPlurality((FStructure) f, headCount);
					if (isPlural)
						return true;
				}
			}
		}
		return false;
	}

	/**
	 * Checks if this FStructureElement is plural by checking its NUM feature.
	 *
	 * @param fsInt
	 *            The FStructureElement that is allegedly plural
	 * @return True if this FStructureElement object is plural
	 */
	public static boolean checkPlurality(FStructureInterface fsInt) {

		String features[] = ((FStructureElement) fsInt).getFeatures();
		for (int i = 0; i < features.length; i++) {
			if (features[i].equals("NUM=plur")) {
				return true;
			}
		}
		return false;
	}

	/**
	 * Gets the names of all the children of the f-structure.
	 *
	 * @param fstruct
	 *            The f-structure to be gotten from
	 * @return A string value containing the names of all the children of this
	 *         FStructure object separated by whitespace
	 */
	public static String getChildren(FStructure fstruct) {
		Enumeration e = fstruct.values.keys();
		FStructureInterface f = null;
		String children = " ";

		while (e.hasMoreElements()) {
			String key = (String) e.nextElement();
			f = (FStructureInterface) fstruct.values.get(key);

			children += f.getName() + " ";
		}
		return children.trim();
	}

	/**
	 * Counts the number of children given an f-structure.
	 *
	 * @param fstruct
	 *            The f-structure to be gotten from
	 * @return The number of children of an f-structure
	 */
	public static int getNumChildren(FStructure fstruct) {
		Enumeration e = fstruct.values.keys();
		FStructureInterface f = null;
		int numChildren = 0;

		while (e.hasMoreElements()) {
			String key = (String) e.nextElement();
			f = (FStructureInterface) fstruct.values.get(key);

			numChildren++;
		}
		return numChildren;
	}

	/**
	 * Checks if all children (first-level elements) of the f-structure have
	 * popped
	 *
	 * @param fstruct
	 *            The f-structure to be searched
	 * @return True if all children of f-structure have popped
	 */
	public static boolean checkIfElementsPoppedFE(FStructure fstruct) {
		Enumeration e = fstruct.values.keys();
		FStructureInterface f = null;

		while (e.hasMoreElements()) {
			String key = (String) e.nextElement();
			f = (FStructureInterface) fstruct.values.get(key);

			if (f instanceof FStructureElement) {
				if (!((FStructureElement) f).fePopped) {
					return false;
				}
			} else {
				if (!((FStructure) f).fePopped) {
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * Retrieves the parent f-structure of the given f-structure recursively and
	 * assigns it to static member variable fsParent
	 *
	 * @param root
	 *            The starting node of the tree to be searched
	 * @param fsInt
	 *            The f-structure object in question
	 */
	public static void getFSParent(FStructure root, FStructureInterface fsInt) {
		Enumeration e = root.values.keys();
		FStructureInterface f = null;

		// System.out.println("Current f-struct is: " + root.getName());
		// if (root.equals(fsInt))
		// fsParent = root;

		while (e.hasMoreElements() && !parentFound) {
			String key = (String) e.nextElement();
			f = (FStructureInterface) root.values.get(key);

			// System.out.println("f is " + f.getName() + " while root is " +
			// root.getName());

			if (f instanceof FStructureElement
					&& fsInt instanceof FStructureElement && !parentFound) {
				if (f == fsInt) {

					fsParent = root;
					parentFound = true;
					return;
				}
			}

			else if (f instanceof FStructure && !parentFound) {
				if (fsInt instanceof FStructure && f == fsInt) {
					fsParent = root;
					parentFound = true;
					return;
				}
				getFSParent((FStructure) f, fsInt);
			}
		}
	}

	/**
	 * Searches the Filipino or English f-structure given the corresponding
	 * token. Assigns the match to static member variable fsRule.
	 *
	 * @param fs
	 *            The f-structure to be searched
	 * @param token
	 *            The token to be compared to
	 * @param dir
	 *            The direction if English to Filipino or Filipino to English
	 */
	public static void searchFStructure(FStructure fs, Object token, String dir) {
		Enumeration e = fs.values.keys();
		FStructureInterface f = null;
		boolean popped;

		if (dir.equalsIgnoreCase("fe"))
			popped = fs.fePopped;
		else
			popped = fs.efPopped;

		while (e.hasMoreElements() && !popped && !fsFound) {
			String key = (String) e.nextElement();
			f = (FStructureInterface) fs.values.get(key);
			if (f instanceof FStructureElement
					&& !((FStructureElement) f).fePopped && !fsFound) {

				FStructureElement fElement = (FStructureElement) f;
				HashSet hs = fElement.getValues();

				Object arrElementValues[] = hs.toArray();
				for (int nCnt = 0; nCnt < arrElementValues.length; nCnt++) {
					if (((FStructureElementString) arrElementValues[nCnt])
							.toString().contains("PRED")
							&& !fElement.fePopped && !fsFound) {

						StringTokenizer tokenizer = new StringTokenizer(
								((FStructureElementString) arrElementValues[nCnt])
										.toString());
						String fElementValue = null;
						while (tokenizer.hasMoreTokens()) {
							fElementValue = (String) tokenizer.nextElement();
						}
						if (fElementValue.equalsIgnoreCase(token.toString())) {
							if (dir.equalsIgnoreCase("fe"))
								fElement.fePopped = true;
							else if (dir.equalsIgnoreCase("ef"))
								fElement.efPopped = true;
							// System.out.println("TIKBOY: FElement is " +
							// fElement.name + " and token is " +
							// token.toString());
							popped = true;
							fsRule = (FStructureInterface) fElement;
							fsFound = true;
							// System.out.println("fsRule is " +
							// fsRule.toString());
							return;
						}
					}
				}
			} else if (f instanceof FStructure && !fsFound) {
				searchFStructure((FStructure) f, token, dir);
			}
		}
	}

	/**
	 * Prints the contents (whole subtree) of a given f-structure to a text
	 * file.
	 *
	 * @param fstruct
	 * @param tabIndent
	 * @param out
	 */
	public static void printFStructureContentsRecursive(FStructure fstruct,
			String tabIndent, PrintWriter out) {
		String key;
		Enumeration e = fstruct.values.keys();
		FStructureInterface f = null;

		while (e.hasMoreElements()) {
			key = (String) e.nextElement();
			f = (FStructureInterface) fstruct.values.get(key);

			out.print(tabIndent + "FS " + f.getName());

			if (f instanceof FStructure) {
				String[] feats = f.getFeatures();

				for (int i = 0; i < feats.length; i++) {
					out.print(" " + feats[i]);
				}
				out.println();
				printFStructureContentsRecursive((FStructure) f, tabIndent
						+ "\t", out);
			} else if (f instanceof FStructureElement) {
				// getElementValue
				FStructureElement fElement = (FStructureElement) f;

				HashSet hs = fElement.getValues();

				Object arrElementValues[] = hs.toArray();
				for (int nCnt = 0; nCnt < arrElementValues.length; nCnt++) {

					// System.out.println("Arr values: " +
					// arrElementValues[nCnt].toString());
					if (((FStructureElementString) arrElementValues[nCnt])
							.toString().contains("PRED")) {

						StringTokenizer tokenizer = new StringTokenizer(
								((FStructureElementString) arrElementValues[nCnt])
										.toString());
						String fElementValue = null;
						while (tokenizer.hasMoreTokens()) {
							fElementValue = (String) tokenizer.nextElement();
						}

						out.print(": \"" + fElementValue + "\"");
					} else {
						/*
						 * StringTokenizer tokenizer = new
						 * StringTokenizer(((FStructureElementString
						 * )arrElementValues[nCnt]).toString()); String
						 * fElementValue = null;
						 * while(tokenizer.hasMoreTokens()){ fElementValue =
						 * (String)tokenizer.nextElement() + "=" +
						 * (String)tokenizer.nextElement(); }
						 *
						 * System.out.print(" " + fElementValue);
						 */
					}
				}
				String features[] = fElement.getFeatures();

				if (features.length >= 1) {
					out.print(" " + features[0]);
				}
				out.println();

				// System.out.println(tabIndent + "YAHOO " + hs.toString());
			}

			else if (f instanceof FStructureSemantics) {
				out.println("Yipee");
			}

			else
				out.println();
		}
	}

	/**
	 * Prints the contents (whole subtree) of a given f-structure on the console
	 * window.
	 *
	 * @param fstruct
	 * @param tabIndent
	 */
	public static void printFStructureContentsRecursive(FStructure fstruct,
			String tabIndent) {
		String key;
		Enumeration e = fstruct.values.keys();
		FStructureInterface f = null;

		while (e.hasMoreElements()) {
			key = (String) e.nextElement();
			f = (FStructureInterface) fstruct.values.get(key);

			System.out.print(tabIndent + "FS " + f.getName());

			if (f instanceof FStructure) {
				String[] feats = f.getFeatures();

				for (int i = 0; i < feats.length; i++) {
					System.out.print(" " + feats[i]);
				}
				System.out.println();
				printFStructureContentsRecursive((FStructure) f, tabIndent
						+ "\t");
			} else if (f instanceof FStructureElement) {
				// getElementValue
				FStructureElement fElement = (FStructureElement) f;

				HashSet hs = fElement.getValues();

				Object arrElementValues[] = hs.toArray();

				/*
				 * for(int oop=0; oop < arrElementValues.length; oop++)
				 * System.out.println(arrElementValues[oop]);
				 */
				for (int nCnt = 0; nCnt < arrElementValues.length; nCnt++) {

					// System.out.println("Arr values: " +
					// arrElementValues[nCnt].toString());
					if (((FStructureElementString) arrElementValues[nCnt])
							.toString().contains("PRED")) {

						StringTokenizer tokenizer = new StringTokenizer(
								((FStructureElementString) arrElementValues[nCnt])
										.toString());
						String fElementValue = null;
						while (tokenizer.hasMoreTokens()) {
							fElementValue = (String) tokenizer.nextElement();
						}

						System.out.print(": \"" + fElementValue + "\""); // System.out.print(" Arr values: "
						// +
						// arrElementValues[nCnt].toString()
						// +
						// " ");
					} else {
						/*
						 * StringTokenizer tokenizer = new
						 * StringTokenizer(((FStructureElementString
						 * )arrElementValues[nCnt]).toString()); String
						 * fElementValue = null;
						 * while(tokenizer.hasMoreTokens()){ fElementValue =
						 * (String)tokenizer.nextElement() + "=" +
						 * (String)tokenizer.nextElement(); }
						 *
						 * System.out.print(" " + fElementValue);
						 */
					}
				}
				String features[] = fElement.getFeatures();
				for (int i = 0; i < features.length; i++)
					System.out.print(" " + features[i]);

				System.out.println();

				// System.out.println(tabIndent + "YAHOO " + hs.toString());
			} else if (f instanceof FStructureSemantics) {
				System.out.println("Yipee");
			}
		}
		// System.out.println();
	}

	/**
	 * Generates the parse productions to be used for filtering and searching
	 * transfer rule sets. This is part of translation
	 *
	 * @param fsInput
	 * @param tokens
	 * @return Vector containing the generated parse productions
	 */
	public static Vector generateParseProductions(FStructure fsInput,
			String tokens[]) {

		Vector vParseProductions = new Vector();

		for (int i = 0; i < tokens.length; i++) {
			fsRule = null;
			fsFound = false;
			searchFStructure(fsInput, tokens[i], "fe");
			// System.out.println("rule name: " + fsRule.getName());
			vParseProductions.add(fsRule.getName());

			FStructureInterface fsCurrent = fsRule;
			if (fsRule == null)
				System.out.println("null");

			boolean popped = true;
			while (!fsCurrent.getName().equals("root") && popped) {
				parentFound = false;
				getFSParent(fsInput, fsCurrent);
				popped = false;
				if (checkIfElementsPoppedFE((FStructure) fsParent)) {
					((FStructure) fsParent).fePopped = true;
					fsCurrent = (FStructure) fsParent;
					popped = true;
					vParseProductions.add(fsCurrent.getName() + " : "
							+ getChildren((FStructure) fsCurrent));
				}
			}
		}

		for (int i = 0; i < vParseProductions.size(); i++) {
			System.out.println("production: "
					+ ((String) vParseProductions.elementAt(i)));
		}

		return vParseProductions;
	}

	/**
	 * Parses the input sentence, generates the parse tree, then lists the parse
	 * productions.
	 *
	 * @param inputSentence
	 * @param cLang
	 * @throws Exception
	 */
	public static void analyzeInput(String inputSentence, char cLang)
			throws Exception {

		PrintWriter writer = new PrintWriter("/home/pckid/LEFT/LOG2.txt");
		LEFTTranslator translator = new LEFTTranslator(writer);
		PrintWriter outWriter = new PrintWriter(
				"/home/pckid/LEFT/training_output.txt");

		Scanner scannerInput = new Scanner();
		FStructure fsInput[] = null; // the array of Filipino f-structures from
		// the corpus
		org.dlsu.mt.parser.dictionary.Dictionary language2Dictionary = new org.dlsu.mt.parser.dictionary.Dictionary(
				"Language2");
		org.dlsu.mt.parser.dictionary.Dictionary language1Dictionary = new org.dlsu.mt.parser.dictionary.Dictionary(
				"Language1");
		AnalysisModule analysis = new AnalysisModule();
		GenerationModule gen = new GenerationModule();
		int numInputTokensBasic = 0;
		String tokens[] = new String[1];

		int l = 0;

		try {
			if (cLang == '1') {
				scannerInput.cLang = '1';
				scannerInput.scanNoGUI(inputSentence, translator);
				analysis.reload("/home/pckid/LEFT/language1.txt",
						language1Dictionary);
			} else if (cLang == '2') {
				scannerInput.cLang = '2';
				scannerInput.scanNoGUI(inputSentence, translator);
				analysis.reload("/home/pckid/LEFT/language2.txt",
						language2Dictionary);
			}
			// gen.loadGrammar("c:/language1.txt");
			fsInput = new FStructure[scannerInput.sentences.size()];
			while (l < scannerInput.sentences.size()) {
				// System.out.println("Enter while");
				if (scannerInput.acceptedSentences.get(l) == true) {
					// outWriter.append(translator.translate1To2(scanner.sentences.get(l).toString())
					// + scanner.punctuation.get(l));

					fsInput[l] = analysis
							.analyzeFilipino(scannerInput.sentences.get(l)
									.toString()
									+ " $");
					// System.out.println("sentence accepted2");
					if (fsInput[l] != null)
						System.out.println("Analysis successful");

					StringTokenizer tokenizer = new StringTokenizer(
							scannerInput.sentences.get(l).toString());
					numInputTokensBasic = tokenizer.countTokens();
					tokens = new String[numInputTokensBasic];
					for (int i = 0; i < numInputTokensBasic; i++) {
						tokens[i] = tokenizer.nextToken();
					}
				}
				l++;
				if (l != scannerInput.sentences.size())
					outWriter.append(" ");
			}

			System.out.println("GIAN IS PRINTING THE CONTENTS");
			printFStructureContentsRecursive(fsInput[0], "\t");
			for (int i = 0; i < numInputTokensBasic; i++) {
				System.out.println("token: " + tokens[i]);
			}

			generateParseProductions(fsInput[0], tokens);
		}

		catch (Exception e) {
			outWriter.println("Error Analyzing Input Sentence using RBE");
		}

		// close the log files
		writer.close();
	}

	/**
	 * Gets the list of candidate rules who has a maximum compositional rule
	 * which matches the given maximum compositional production.
	 *
	 * @param aTransferRuleSetList
	 * @param maxCompProd
	 * @param cLang
	 *            The direction of translation
	 * @return An array of vectors containing the candidate list
	 */
	public static Vector[] getCandidateList(Vector aTransferRuleSetList[],
			String maxCompProd, char cLang) {
		// SELECT * FROM hybridTransferRule WHERE transferRule =
		// maximumCompositionalProduction
		String query1 = new String();
		String query2 = new String();
		if (cLang == '1') {
			query1 = "SELECT COUNT(*) AS count FROM hybridTransferRules WHERE engSide ='"
					+ maxCompProd + "';";
			// query1 =
			// "SELECT COUNT (hybridTransferRules.ruleSet) AS count FROM hybridTransferRules WHERE ruleSet IN (SELECT ruleSet FROM hybridTransferRules WHERE engSide ='"
			// + maxCompProd + "');";
			query2 = "SELECT ruleSet FROM hybridTransferRules WHERE engSide ='"
					+ maxCompProd + "';";
			// query2 =
			// "SELECT filSide, engSide, ruleSet FROM hybridTransferRules WHERE ruleSet IN (SELECT ruleSet FROM hybridTransferRules WHERE engSide ='"
			// + maxCompProd + "');";
		} else {
			query1 = "SELECT COUNT(*) AS count FROM hybridTransferRules WHERE filSide ='"
					+ maxCompProd + "';";
			// query1 =
			// "SELECT COUNT (hybridTransferRules.ruleSet) AS count FROM hybridTransferRules WHERE ruleSet IN (SELECT ruleSet FROM hybridTransferRules WHERE filSide ='"
			// + maxCompProd + "');";
			query2 = "SELECT ruleSet FROM hybridTransferRules WHERE filSide ='"
					+ maxCompProd + "';";
			// query2 =
			// "SELECT filSide, engSide, ruleSet FROM hybridTransferRules WHERE ruleSet IN (SELECT ruleSet FROM hybridTransferRules WHERE filSide ='"
			// + maxCompProd + "');";
		}

		try {
			Class.forName("com.mysql.jdbc.Driver");
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/leftDB", "root", "");
			Statement stmt = con.createStatement();
			System.out.println("QUERY is " + query1);
			ResultSet rs1 = stmt.executeQuery(query1);

			Vector vTransferRuleSet = new Vector();

			String filSide = null, engSide = null, ruleSet = null;
			int count = 0;

			while (rs1.next()) {
				count = Integer.parseInt(rs1.getString("count"));
			}
			aTransferRuleSetList = new Vector[count];

			if (rs1 != null) {
				rs1.close();
			}

			ResultSet rs2 = stmt.executeQuery(query2);
			int i = 0;
			while (rs2.next()) {
				aTransferRuleSetList[i++] = loadTransferRuleSet(rs2
						.getString("ruleSet"));
			}
			System.out.println("i = " + i + " count = " + count);
			if (rs2 != null) {
				rs2.close();
				// con.close();
			}
			con.close();
			return aTransferRuleSetList;
		} catch (Exception e) {
			System.out.println("Connection to database failed!");
			e.printStackTrace();
			return null;
		}
	}

	/**
	 * Searches for an f-structure from the root of a tree or subtree and the
	 * string name of the f-structure and returns the f-structure object.
	 *
	 * @param root
	 *            The starting node of the search
	 * @param fsName
	 *            The name of the f-structure to be searched
	 * @param cLang
	 * @return The actual f-structure object of the found f-structure
	 */
	public static FStructureInterface searchFStructure(FStructure root,
			String fsName, char cLang) {
		Enumeration e = root.values.keys();
		FStructureInterface f = null;
		boolean popped;

		if (cLang == '2')
			popped = root.fePopped;
		else
			popped = root.efPopped;

		while (e.hasMoreElements()) {
			String key = (String) e.nextElement();
			f = (FStructureInterface) root.values.get(key);

			if (f.getName().trim().equals(fsName.trim())) {
				if (f instanceof FStructure)
					return (FStructure) f;
				else if (f instanceof FStructureElement)
					return f;
			}
		}
		return root;
	}

	/**
	 * Searches the matching transfer rule from a list of applicable rule sets
	 * given a parse production.
	 *
	 * @param applicableRuleSet
	 * @param parseProduction
	 * @param cLang
	 * @return The matching TransferRule object
	 */
	public static TransferRule searchMatchingTransferRule(
			Vector applicableRuleSet, String parseProduction, char cLang) {

		// English to Fiipino
		if (cLang == '1') {
			for (int i = 0; i < applicableRuleSet.size(); i++) {

				if ( ((TransferRule) applicableRuleSet.elementAt(i)).engSide.equals(parseProduction)) {
					return (TransferRule) applicableRuleSet.elementAt(i);
				}
			}
		}
		// Filipino to English
		else {
			for (int i = 0; i < applicableRuleSet.size(); i++) {

				if ( ((TransferRule) applicableRuleSet.elementAt(i)).filSide.equals(parseProduction)) {
					return (TransferRule) applicableRuleSet.elementAt(i);
				}
			}
		}
		return null;
	}

	/**
	 * Creates or expands the target f-structure recursively where the transfer
	 * rules are taken from the applicable rule sets.
	 *
	 * @param applicableRuleSet
	 * @param rootSource
	 * @param rootTarget
	 * @param cLang
	 */
	public static void expandTargetStructureRecursive(
			Vector applicableRuleSet, FStructureInterface rootSource,
			FStructureInterface rootTarget, char cLang) {

		TransferRule tr = null;

		if (rootSource instanceof FStructure) {
			tr = searchMatchingTransferRule(applicableRuleSet, rootSource
					.getName()
					+ " : " + getChildren((FStructure) rootSource), cLang);
		} else if (rootSource instanceof FStructureElement) {
			tr = searchMatchingTransferRule(applicableRuleSet, rootSource
					.getName(), cLang);
		}

		if (rootTarget instanceof FStructure) {
			if (cLang == '1') {

				if(tr.leftHandSideFil == null) // if compositional rule targetside is null, no need to expand
					return;
				rootTarget = searchFStructure((FStructure) rootTarget,
						tr.leftHandSideFil, cLang);
			} else {
				if(tr.leftHandSideEng == null) // if compositional rule targetside is null, no need to expand
					return;
				rootTarget = searchFStructure((FStructure) rootTarget,
						tr.leftHandSideEng, cLang);
			}
		}

		// creates children
		if (rootTarget instanceof FStructure) {
			if (cLang == '1') {

				String[] filChildren = tr.getFilChildren();
				for (int i = 0; i < tr.getNumFilChildren(); i++) {
					if (filChildren[i].charAt(0) > 64
							&& filChildren[i].charAt(0) < 91)
						((FStructure) rootTarget).addEntry(new FStructure(
								filChildren[i]));
					else
						((FStructure) rootTarget)
								.addEntry(new FStructureElement(filChildren[i]));
				}
			} else if (cLang == '2') {
				String[] engChildren = tr.getEngChildren();
				for (int i = 0; i < tr.getNumEngChildren(); i++) {
					if (engChildren[i].charAt(0) > 64
							&& engChildren[i].charAt(0) < 91)
						((FStructure) rootTarget).addEntry(new FStructure(
								engChildren[i]));
					else
						((FStructure) rootTarget)
								.addEntry(new FStructureElement(engChildren[i]));
				}
			}

			String key;
			Enumeration e = ((FStructure) rootSource).values.keys();
			FStructureInterface f = null;

			while (e.hasMoreElements()) {
				key = (String) e.nextElement();
				f = (FStructureInterface) ((FStructure) rootSource).values
						.get(key);

				if (f instanceof FStructureElement) {

					FStructureElement fElement = (FStructureElement) f;

					HashSet hs = fElement.getValues();

					Object arrElementValues[] = hs.toArray();
					for (int nCnt = 0; nCnt < arrElementValues.length; nCnt++) {

						if (((FStructureElementString) arrElementValues[nCnt])
								.toString().contains("PRED")) {

							StringTokenizer tokenizer = new StringTokenizer(
									((FStructureElementString) arrElementValues[nCnt])
											.toString());
							String fElementValue = null;
							while (tokenizer.hasMoreTokens()) {
								fElementValue = (String) tokenizer
										.nextElement();
							}

							tr = searchMatchingTransferRule(applicableRuleSet,
									f.getName(), cLang);

							FStructureInterface currTarget;

							if (cLang == '1') {
								currTarget = searchFStructure(
										(FStructure) rootTarget, tr.filSide,
										cLang);

							} else {
								currTarget = searchFStructure(
										(FStructure) rootTarget, tr.engSide,
										cLang);
							}

							String translatedWord = translateWord(fElementValue, currTarget.getName(),
									cLang);

							if(currTarget instanceof FStructureElement) {
								((FStructureElement) currTarget)
								.addElement(new FStructureElementString(
										"PRED\t"
										+ translatedWord));

								((FStructureElement) currTarget)
								.addElement(new FStructureElementString(
										"SOURCE\t" +	fElementValue));

								String features[] = getWordFeatures(translatedWord, cLang);
								for (int i = 0; i < features.length; i++) {

									if (!features[i].contains("PRED")) {
										((FStructureElement) currTarget)
										.addElement(new FStructureElementString(
												features[i].replace('=',
												'\t')));
									}
								}
							}
						}
					}
				} else if (f instanceof FStructureSemantics) {

				} else if (f instanceof FStructure) {
					expandTargetStructureRecursive(applicableRuleSet, f,
							rootTarget, cLang);
				}
			}
		} else if (rootTarget instanceof FStructureElement) {

		}
		// create children
		// for each child of rootSource
		// recursive(applicableRuleSets,
	}

	/**
	 * Gets the lfg features from the monolingual lexicon of a given word.
	 *
	 * @param word
	 *            The word where the features will be taken from
	 * @param cLang
	 *            The target language
	 * @return An String array containing the features of the given word
	 */
	public static String[] getWordFeatures(String word, char cLang) {

		String query = new String();
		String tbl;

		if (cLang == '2')
			tbl = "language1Dict";
		else
			tbl = "language2Dict";

		try {
			Class.forName("com.mysql.jdbc.Driver");
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/leftDB", "root", "");
			Statement stmt = con.createStatement();

			query = "SELECT lfg FROM "
						+ tbl
						+ " WHERE word = '"	+ word + "'";

			ResultSet rs = stmt.executeQuery(query);

			if (rs.next()) {
				String featureString = rs.getString("lfg");

				if(featureString.length() == 0) {
					con.close();
					return new String[0];
				}

				StringTokenizer tokenizer = new StringTokenizer(featureString, ";");
				HashSet<String> hs = new HashSet<String>();

				while(tokenizer.hasMoreTokens()) {
					String elem = tokenizer.nextElement().toString();
					int eqInd = elem.indexOf("=");
					if(eqInd != 0 && eqInd != -1) {
						CharSequence sub = elem.subSequence(0, eqInd);
						elem = elem.replace(sub, sub.toString().toUpperCase());
					}
					hs.add(elem);
				}

				con.close();

				return (String[]) hs.toArray(new String[0]);
			}

		} catch (Exception e) {
			System.out.println("Problem with database or SQL query!");
			e.printStackTrace();
		}
		return new String[0];

	}

	/**
	 * Gets the equivalent word in the target language given a word in the
	 * source language.
	 *
	 * @param sourceWord
	 */
	public static String translateWord(String sourceWord, String targetPOS,
			char cLang) {

		TExtLexicon lex;
		if (cLang == '2')
			lex = new TExtLexicon('e');
		else
			lex = new TExtLexicon('f');

		Vector targetWords = lex.lookup(sourceWord);

		if(targetWords == null)
			return sourceWord;

		for (int i = 0; i < targetWords.size(); i++) {
			if (checkWord((String) targetWords.elementAt(i), targetPOS, cLang)) {
				return (String) targetWords.elementAt(i);
			}
		}
		return sourceWord;
	}

	/**
	 * Checks if an entry containing the word and POS exists in the monolingual
	 * lexicon.
	 *
	 * @param word
	 * @param pos
	 * @param cLang
	 * @return True if such an entry exists
	 */
	public static boolean checkWord(String word, String pos, char cLang) {

		String dict;

		if (cLang == '2')
			dict = "language1Dict";
		else
			dict = "language2Dict";

		String query = "SELECT * FROM " + dict + " WHERE word ='" + word
				+ "' AND pos ='" + pos + "';";

		try {
			Class.forName("com.mysql.jdbc.Driver");
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/leftDB", "root", "");
			Statement stmt = con.createStatement();
			ResultSet rs = stmt.executeQuery(query);

			if (rs.next()) {
				rs.close();
				return true;
			}
			con.close();
		} catch (Exception e) {
			System.out.println("Connection to database failed!");
			e.printStackTrace();
			return false;
		}
		return false;
	}

	/**
	 * Creates a complete FStructure from parsing a given sentence to be used
	 * for testing.
	 *
	 * @return A complete FStructure
	 * @throws Exception
	 */
	public static FStructure createFStruct(String inputSentence, char cLang)
			throws Exception {

		// char cLang = '2';
		// String inputSentence = "Ang bata ay naglalaro.";
		PrintWriter writer = new PrintWriter("/home/pckid/LEFT/LOG2.txt");

		boolean hasCandidate = false;
		boolean isApplicable = true;
		boolean failAnalysis = false;
		boolean exceptionRBE = false;

		LEFTTranslator translator = new LEFTTranslator(writer);
		Scanner scannerInput = new Scanner();
		AnalysisModule analysis = new AnalysisModule();
		FStructure fsInput[] = null; // the array of Filipino f-structures from
		// the corpus
		int numInputTokensBasic = 0;
		String tokens[] = new String[1];
		org.dlsu.mt.parser.dictionary.Dictionary language2Dictionary = new org.dlsu.mt.parser.dictionary.Dictionary(
				"Language2");
		org.dlsu.mt.parser.dictionary.Dictionary language1Dictionary = new org.dlsu.mt.parser.dictionary.Dictionary(
				"Language1");

		Vector applicableRuleSets = new Vector(); // group of applicable rule
		// sets
		Vector vParseProductions = new Vector();
		Vector<TransferRule> vTransferRuleSet = new Vector();
		Vector<TransferRule> aTransferRuleSetList[] = new Vector[1];
		// set of candidates, query where max prod = max comp rule

		int l = 0;

		try {
			if (cLang == '1') {
				scannerInput.cLang = '1';
				scannerInput.scanNoGUI(inputSentence, translator);
				analysis.reload("/home/pckid/LEFT/language1.txt",
						language1Dictionary);
			} else if (cLang == '2') {
				scannerInput.cLang = '2';
				scannerInput.scanNoGUI(inputSentence, translator);
				analysis.reload("/home/pckid/LEFT/language2.txt",
						language2Dictionary);
			}
			// gen.loadGrammar("c:/language1.txt");
			fsInput = new FStructure[scannerInput.sentences.size()];
			while (l < scannerInput.sentences.size()) {
				// System.out.println("Enter while");
				if (scannerInput.acceptedSentences.get(l) == true) {
					// outWriter.append(translator.translate1To2(scanner.sentences.get(l).toString())
					// + scanner.punctuation.get(l));

					fsInput[l] = analysis
							.analyzeFilipino(scannerInput.sentences.get(l)
									.toString()
									+ " $");
					// System.out.println("sentence accepted2");
					if (fsInput[l] != null) {
						System.out.println("Analysis successful");
						// translationOut.println("Analysis successful\r\n");
					} else {
						failAnalysis = true;
					}

					StringTokenizer tokenizer = new StringTokenizer(
							scannerInput.sentences.get(l).toString());
					numInputTokensBasic = tokenizer.countTokens();
					tokens = new String[numInputTokensBasic];
					for (int i = 0; i < numInputTokensBasic; i++) {
						tokens[i] = tokenizer.nextToken();
					}
				}
				l++;
				if (l != scannerInput.sentences.size())
					;// translationOut.println("There are no more input sentences;");
			}

			// System.out.println("SOURCE TREE: ");
			// printFStructureContentsRecursive(fsInput[0],"\t");
			return fsInput[0];

		} catch (Exception e) {
			System.out.println("ERROR in creating fstruct createFStruct");
		}

		return null;
	}

	/**
	 * Applies a unification rule to a given FStructure in order to correct
	 * semantical errors. A feature-value pair is to be propagated either
	 * upwards or downwards or a combination of both as stated by the parameter,
	 * rule.
	 *
	 * @param fstruct
	 *            The FStructure where the unification rule will be applied to
	 * @param root
	 *            The FStructure of the whole sentence where fstruct belongs to,
	 *            necessary for getting the parent of an FStructure
	 * @param rule
	 *            The rule to be applied
	 * @param feature
	 *            The feature to be propagated within the parse tree
	 * @return The resulting FStructure after applying the unification rule
	 */
	public static FStructure applyUnificationRule(FStructure fstruct,
			FStructure root, String[] rule, String feature) {

		int i = 0;

		FStructureInterface child = getChildFStruct(fstruct, rule[i]);

		while (child != null && i + 1 < rule.length) {

			String featureValue = null; // the feature-value pair to be
			// propagated

			if (child != null) {
				// the list of all the feature-value pairs of the child
				String[] childFeatures = child.getFeatures();

				for (int j = 0; j < childFeatures.length; j++) {
					// look for the feature-value pair to be propagated within
					// the list of features
					if (childFeatures[j] != null
							&& childFeatures[j].trim().regionMatches(true, 0,
									new String(feature.trim()), 0, feature.length())) {
						featureValue = childFeatures[j];
					}
				}

				i++;

				if (rule[i].trim().equals("/")) { // propagate upwards
					i++;

					FStructureInterface parent; // look for the parent of child
					parentFound = false;
					getFSParent(root, child);
					parent = fsParent;

					HashSet hs = parent.getFeaturesAlias();
					Object[] parentFeatures = hs.toArray();
					child = parent;

					for (int j = 0; j < parentFeatures.length; j++) {
						// look for the previous value of the feature to be
						// propagated and delete the value
						if (parentFeatures[j].toString().trim().regionMatches(true, 0,
								new String(feature.trim()), 0, feature.length())) {
							hs.remove(parentFeatures[j]);
						}
					}
					if (featureValue != null) {
						// add the new feature-value pair to the
						// FStructureInterface
						parent.addElement(new FStructureElementString(
								featureValue.replace('=', '\t')));
					}

				} else { // propagate downwards
					i++;

					FStructureInterface grandChild = getChildFStruct(
							(FStructure) child, rule[i]);
					HashSet hs = grandChild.getFeaturesAlias();
					Object[] grandChildFeatures = hs.toArray();
					child = grandChild;

					for (int j = 0; j < grandChildFeatures.length; j++) {
						// look for the previous value of the feature to be
						// propagated and delete the value
						if (grandChildFeatures[j].toString().trim().regionMatches(
								true, 0, new String(feature.trim()), 0, feature.length())) {
							hs.remove(grandChildFeatures[j]);
						}
					}
					if (featureValue != null) {
						// add the new feature-value pair to the
						// FStructureInterface
						grandChild.addElement(new FStructureElementString(
								featureValue.replace('=', '\t')));

					}
				}
			}
		}
		return fstruct;
	}

	/**
	 * (Deprecated: see correctFStruct) Traverse to the deepest level
	 * (Depth-First Search) and apply rules going upward.
	 *
	 * @deprecated
	 * @param fs
	 * @param root
	 * @param tabIndent
	 */
	public static void treeWalk(FStructureInterface fs, FStructure root) {

		System.out.println(fs.getName());

		if (getChildren((FStructure) fs).contains("SUBJ")) {
			treeWalk(getChildFStruct((FStructure) fs, "SUBJ"), root);
		} else if (getChildren((FStructure) fs).contains("NPCOORD")) {
			treeWalk(getChildFStruct((FStructure) fs, "NPCOORD"), root);
		} else if (getChildren((FStructure) fs).contains("HEAD")) {
			treeWalk(getChildFStruct((FStructure) fs, "HEAD"), root);
		}

		String rule[] = (String[]) uRulesEng.get(fs.getName() + ":"
				+ getChildren((FStructure) fs));

		if (rule != null) {
			applyUnificationRule((FStructure) fs, root, rule, "NUM");
		}
	}

	/**
	 * Checks if all children of this F-structure have already been marked.
	 *
	 * @param fstruct
	 *            The F-structure to be checked
	 * @return True if all children of this F-structure have been marked
	 */
	public static boolean allChildrenMarked(FStructure fstruct) {

		Enumeration e = fstruct.values.keys();
		FStructureInterface f = null;

		while (e.hasMoreElements()) {
			String key = (String) e.nextElement();
			f = (FStructureInterface) fstruct.values.get(key);

			if (f instanceof FStructure) {
				if (!((FStructure) f).unifMarked) {
					return false;
				}
			}
		}
		return true;
	}

	/**
	 * Makes this f-struct plural by changing its NUM feature value.
	 *
	 * @param fstruct
	 *            The f-structure to be made plural
	 */
	public static void makePlural(FStructure fstruct) {

		String feature = "NUM";

		// Make this plural
		HashSet hs = fstruct.getFeaturesAlias();
		Object[] features = hs.toArray();
		for (int j = 0; j < features.length; j++) {
			// look for the previous value of the feature to be
			// propagated and delete the value
			if (features[j].toString().regionMatches(true, 0,
					new String(feature.trim()), 0, 3)) {
				hs.remove(features[j]);
			}
		}
		fstruct.addElement(new FStructureElementString(new String(feature
				+ "\tplur")));
	}

	/**
	 * Traverse to the deepest level (depth-first style) and recursively applies
	 * unification rules going upward and outward. After transfer, the target
	 * f-structure might contain (grammatical) errors, and must therefore be
	 * corrected by applying unification rules.
	 *
	 * @param fstruct
	 *            The current structure
	 * @param root
	 *            The root structure of the sentence
	 */
	public static void correctFStruct(FStructure fstruct, FStructure root,
			char cLang) {

		// Find suitable unification rule and apply
		String[] rule;
		// The feature in focus
		String[] features = {"PERS", "NUM", "CONT"};

		if (cLang == '1')
			rule = (String[]) uRulesFil.get(fstruct.getName() + " : "
					+ getChildren((FStructure) fstruct));
		else
			rule = (String[]) uRulesEng.get(fstruct.getName() + " : "
					+ getChildren((FStructure) fstruct));

		if (allChildrenMarked((FStructure) fstruct)) {

			if (rule != null) {
				//DONE: Apply unification rules with several features
				for(int i=0; i<features.length; i++)
					applyUnificationRule((FStructure) fstruct, root, rule, features[i]);
			}

			// Check if structure is SUBJ, and has multiple HEADs. If so,
			// make this structure plural

			headCountGlobal = 0;
			if (fstruct.getName().equals("SUBJ") && checkPlurality(fstruct, 0)) {
				makePlural(fstruct);
			}
			((FStructure) fstruct).unifMarked = true;

		} else {
			Enumeration e = fstruct.values.keys();
			FStructureInterface f = null;

			while (e.hasMoreElements()) {
				String key = (String) e.nextElement();
				f = (FStructureInterface) fstruct.values.get(key);

				if (f instanceof FStructure) {
					correctFStruct((FStructure) f, root, cLang);
				}
			}

			if (rule != null) {
				//DONE: Apply unification rules with several features
				for(int i=0; i<features.length; i++)
					applyUnificationRule((FStructure) fstruct, root, rule, features[i]);
			}

			headCountGlobal = 0;
			if (fstruct.getName().equals("SUBJ") && checkPlurality(fstruct, 0)) {
				makePlural(fstruct);
			}
			((FStructure) fstruct).unifMarked = true;
		}
	}

	/**
	 * Adds individual rules to the Hashtable uRulesEng, the set of all global
	 * English unification rules.
	 */
	public static void populateUnificationRulesEng() {

		uRulesEng = new Hashtable();
		ArrayList<String> list = new ArrayList<String>();
		String[] rule = new String[1];

		list.clear();
		list.add("SUBJ");
		list.add("/");
		list.add("ROOT");
		list.add("\\");
		list.add("aux");

		uRulesEng.put("root : aux SUBJ verb", list.toArray(rule.clone()));

		list.clear();
		list.add("noun");
		list.add("/");
		list.add("HEAD");

		uRulesEng.put("HEAD : noun", list.toArray(rule.clone()));

		list.clear();
		list.add("HEAD");
		list.add("/");
		list.add("SUBJ");

		uRulesEng.put("SUBJ : det HEAD", list.toArray(rule.clone()));

	}

	/**
	 * Adds individual rules to the Hashtable uRulesEng, the set of all global
	 * Filipino unification rules.
	 */
	public static void populateUnificationRulesFil() {

		uRulesFil = new Hashtable();
		ArrayList<String> list = new ArrayList<String>();
		String[] rule = new String[1];

		list.clear();
		list.add("mga");
		list.add("/");
		list.add("PLURDET");

		uRulesFil.put("PLURDET : mga", list.toArray(rule.clone()));

		list.clear();
		list.add("proper");
		list.add("/");
		list.add("HEAD");

		uRulesFil.put("HEAD : proper", list.toArray(rule.clone()));

		list.clear();
		list.add("HEAD");
		list.add("/");
		list.add("SUBJ");
		list.add("\\");
		list.add("nom");

		uRulesFil.put("SUBJ : nom HEAD", list.toArray(rule.clone()));
	}

	/**
	 * The main method.
	 *
	 * @param args
	 */
	public static void main(String[] args) throws Exception {

		text.util.DBConnector dbConnector = new text.util.DBConnector();
		dbConnector.connect();
		//hybridTrain();
		//populateUnificationRulesEng();
		hybridTranslate();
		text.util.DBConnector.close();

		/*
		// cLang = 1 for English, cLang = 2 for Filipino
		char cLang = '1';
		FStructure fs = createFStruct("The child are playing.", cLang);
		FStructure top = new FStructure("TOP");
		top.addEntry(fs);

		headCountGlobal = 0;
		if (checkPlurality((FStructure) fs, 0))
			System.out.println("Yes it's PLURAL");
		else
			System.out.println("No it's SINGULAR");

		printFStructureContentsRecursive((FStructure) fs, "\t");
		System.out.println();
		correctFStruct(top, top, cLang);
		printFStructureContentsRecursive((FStructure) fs, "\t");
		replaceSourceWordsWithTarget(fs);
		*/
	}

	/**
	 * Checks if given array's elements contain key as a substring.
	 *
	 * @param list The array
	 * @param key The key to be searched
	 * @return True if key is found
	 */
	public static boolean elementSubstr(Object[] list, String key) {

		for(int i = 0; i < list.length; i++) {
			if(list[i].toString().contains(key))
				return true;
		}
		return false;
	}

	/**
	 * Places the words that should appear in the final output after unification
	 * into the target f-structure. This should be the last step before going
	 * through the HTPL interpreter.
	 *
	 * @param fstruct The unified f-structure
	 */
	public static void replaceSourceWordsWithTarget(FStructure fstruct, char cTarget) {

		// Visit all nodes
		// For each terminal node in the tree, query database
		String key;
		Enumeration e = fstruct.values.keys();
		FStructureInterface f = null;

		String actualWord = null;
		String correctWord = null;

		while (e.hasMoreElements()) {
			key = (String) e.nextElement();
			f = (FStructureInterface) fstruct.values.get(key);

			if (f instanceof FStructure) {
				replaceSourceWordsWithTarget((FStructure) f, cTarget);

			} else if (f instanceof FStructureElement) {

				FStructureElement fElement = (FStructureElement) f;
				HashSet hs = fElement.getValues();
				Object[] arrElementValues = hs.toArray();

				String pos = null;
				// if rule was filSide=nom, engSide=null
				if(f.getName().equals("nom") && !elementSubstr(arrElementValues, "PRED")) {
					f.addElement(new FStructureElementString("PRED\t" + "ang"));
					pos = "nom";
					arrElementValues = hs.toArray();
				}

				for (int nCnt = 0; nCnt < arrElementValues.length; nCnt++) {

					if (((FStructureElementString) arrElementValues[nCnt])
							.toString().contains("PRED")) {

						StringTokenizer tokenizer = new StringTokenizer(
								((FStructureElementString) arrElementValues[nCnt])
										.toString());
						String fElementValue = null;
						while (tokenizer.hasMoreTokens()) {
							fElementValue = (String) tokenizer.nextElement();
						}
						actualWord = fElementValue;

					} else {

					}
				}

				String numFeature = null;
				String sourceWord = null;

				String features[] = fElement.getFeatures();
				for (int i = 0; i < features.length; i++) {
					if(features[i].contains("NUM=")) {
						numFeature = features[i];
					}
					else if(features[i].contains("SOURCE=")) {
						sourceWord = features[i].replace("SOURCE=", "");
					}
				}

				// check first if actualWord matches the feature of fstruct
				if(features != null && !checkWordMatchFeature(actualWord, features, cTarget)) {
					correctWord = getCorrectWord(sourceWord, features, pos, cTarget);

					// remove incorrect word
					for(int i=0; i<arrElementValues.length; i++) {
						if(arrElementValues[i].toString().contains("PRED"))
							hs.remove(arrElementValues[i]);
					}

					// add correct word
					f.addElement(new FStructureElementString("PRED\t" + correctWord));
				}

			} else if (f instanceof FStructureSemantics) {
				System.out.println("SZEMANTICS");
			}
		}
	}

	/**
	 * Checks if the actual word in the f-structure matches the feature in the
	 * database.
	 *
	 * @param word
	 *            The actual word
	 * @param features
	 *            The list of features that the actual word should have
	 * @param cLang
	 *            The language that the word is in
	 * @return True if the word matches the feature entry in the database
	 */
	public static boolean checkWordMatchFeature(String word, String[] features, char cLang) {

		String query = new String();
		String tbl;
		boolean hasFeatures = false;

		if (cLang == '1')
			tbl = "language1Dict";
		else
			tbl = "language2Dict";

		//DONE: Might want to correct this so as to query only once with several "LIKE" clauses
		query = "SELECT COUNT(*) AS count FROM " + tbl + " WHERE word='" + word + "'";

		for(int i=0; i<features.length; i++) {

			if(!features[i].contains("PRED") && !features[i].contains("SOURCE")) {
				query = query + " AND lfg LIKE '%" + features[i].trim() + "%'";
				hasFeatures = true;
			}
		}

		if(!hasFeatures)
			return true;

		try {
			Class.forName("com.mysql.jdbc.Driver");
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/leftDB", "root", "");
			Statement stmt = con.createStatement();

			ResultSet rs = stmt.executeQuery(query);

			if (rs.next()) {
				if(rs.getInt("count") == 0)
					return false;
			}
			else return false;

			con.close();

		} catch (Exception e) {
			System.out.println("Connection to database failed!");
			e.printStackTrace();
		}
		return true;
	}

	/**
	 * Gets the correct word that should be in the f-strucutre, given the features.
	 *
	 * @param word The actual word in the f-structure
	 * @param features The feature that the actual word should have
	 * @param cTargetLang The target language to tell which table to search in
	 *
	 * @return The correct word that should be placed in the final f-structure
	 */
	public static String getCorrectWord(String word, String[] features, String pos,
			char cTargetLang) {

		String query = new String();
		String tbl;

		if (cTargetLang == '2')
			tbl = "language1Dict";
		else
			tbl = "language2Dict";

		try {
			Class.forName("com.mysql.jdbc.Driver");
			Connection con = DriverManager.getConnection(
					"jdbc:mysql://localhost:3306/leftDB", "root", "");
			Statement stmt = con.createStatement();

			if(pos == null) {
				query = "SELECT * FROM "
					+ tbl
					+ " WHERE id IN (SELECT translation from transferDict WHERE word='"
					+ word + "')";
			}
			else
				query = "SELECT * FROM "
					+ tbl
					+ " WHERE pos = '" + pos + "' ";

			if(features != null) {
				for(int i=0; i<features.length; i++) {
					if(!features[i].contains("PRED") && !features[i].contains("SOURCE"))
					query = query + " AND lfg LIKE '%" + features[i].trim() + "%'";
				}
			}
			System.out.println("QUERY is " + query);
			ResultSet rs = stmt.executeQuery(query);

			while (rs.next()) {
				String correctWord = rs.getString("word");
				return correctWord;
			}

			con.close();

		} catch (Exception e) {
			System.out.println("Connection to database failed!");
			e.printStackTrace();
		}
		return null;
	}

	/**
	 * Realizes the readable sentence form given a f-structure and target
	 * language.
	 *
	 * @param f
	 *            The f-structure to be realized
	 * @param cTarget
	 *            The target language
	 * @return The readable sentence form of the given f-structure
	 */
	public static String realizeSentence(FStructure f, char cTarget) {
		String grammarFile = null;
		GenerationModule gm = null;

		if (cTarget == '1') {
			grammarFile = "/home/pckid/LEFT/language2.txt";
		} else if (cTarget == '2') {
			grammarFile = "/home/pckid/LEFT/language1.txt";
		}
		try {
			gm = new GenerationModule(grammarFile);
		} catch (Exception e) {
			System.out.println("Error creating generation module");
			e.printStackTrace();
		}
		if (gm != null) {
			System.out.println("Generation module instantiated");
			try {
				return gm.generateString(f);
			} catch (Exception e) {
				System.out.println("Problem realizing sentence");
				e.printStackTrace();
			}
		}
		return null;
	}

	/**
	 * Commences the translation process.
	 *
	 * @throws Exception
	 */
	public static void hybridTranslate() throws Exception {

		// cLang = '1' English to Filipino, cLang = '2' Filipino to English
		char cLang = '1';
		String inputSentence = "Then she went to the palace to return the sheep and give the gold to the datu.";
		//String inputSentence = "Students are buying books.";
		PrintWriter writer = new PrintWriter("/home/pckid/LEFT/LOG2.txt");
		boolean hasCandidate = false;
		boolean isApplicable = true;
		boolean failAnalysis = false;
		boolean exceptionRBE = false;

		if (cLang == '1')
			populateUnificationRulesFil();
		else populateUnificationRulesEng();

		LEFTTranslator translator = new LEFTTranslator(writer);
		Scanner scannerInput = new Scanner();
		AnalysisModule analysis = new AnalysisModule();
		// the array of Filipino f-structures from the corpus
		FStructure fsInput[] = null;
		int numInputTokensBasic = 0;
		String tokens[] = new String[1];
		org.dlsu.mt.parser.dictionary.Dictionary language2Dictionary = new org.dlsu.mt.parser.dictionary.Dictionary(
				"Language2");
		org.dlsu.mt.parser.dictionary.Dictionary language1Dictionary = new org.dlsu.mt.parser.dictionary.Dictionary(
				"Language1");

		Vector applicableRuleSets = new Vector(); // group of applicable rule
		// sets
		Vector vParseProductions = new Vector();
		Vector<TransferRule> vTransferRuleSet = new Vector();
		// set of candidates, query where max prod = max comp rule
		Vector<TransferRule> aTransferRuleSetList[] = new Vector[1];

		translationOut = new PrintWriter("/home/pckid/LEFT/translationOut.txt");
		translationOut.println("The input sentence is: " + inputSentence);

		int l = 0;

		try {
			if (cLang == '1') {
				scannerInput.cLang = '1';
				scannerInput.scanNoGUI(inputSentence, translator);
				analysis.reload("/home/pckid/LEFT/language1.txt",
						language1Dictionary);
			} else if (cLang == '2') {
				scannerInput.cLang = '2';
				scannerInput.scanNoGUI(inputSentence, translator);
				analysis.reload("/home/pckid/LEFT/language2.txt",
						language2Dictionary);
			}

			fsInput = new FStructure[scannerInput.sentences.size()];
			while (l < scannerInput.sentences.size()) {

				failAnalysis = false;

				if (scannerInput.acceptedSentences.get(l) == true) {
					// outWriter.append(translator.translate1To2(scanner.sentences.get(l).toString())
					// + scanner.punctuation.get(l));

					fsInput[l] = analysis
							.analyzeEnglish(scannerInput.sentences.get(l)
									.toString()
									+ " $");

					if (fsInput[l] != null) {
						System.out.println("Analysis successful");
						translationOut.println("Analysis successful\r\n");
					} else {
						failAnalysis = true;
					}

					StringTokenizer tokenizer = new StringTokenizer(
							scannerInput.sentences.get(l).toString());
					numInputTokensBasic = tokenizer.countTokens();
					tokens = new String[numInputTokensBasic];
					for (int i = 0; i < numInputTokensBasic; i++) {
						tokens[i] = tokenizer.nextToken();
					}
				}
				l++;
				if (l != scannerInput.sentences.size())
					translationOut
							.println("There are no more input sentences;");
			}

			System.out.println("SOURCE TREE: ");
			printFStructureContentsRecursive(fsInput[0], "\t");

			vParseProductions = generateParseProductions(fsInput[0], tokens);

			translationOut.println("Parse Productions are: ");
			for (int i = 0; i < vParseProductions.size(); i++) {
				translationOut.println(vParseProductions.elementAt(i));
			}

			aTransferRuleSetList = getCandidateList(aTransferRuleSetList,
					(String) vParseProductions.elementAt(vParseProductions
							.size() - 1), cLang);

			// query for candidate set (maximum compositional rule)
			// aTransferRuleSetList[0] = loadTransferRuleSet("001214927713593");

			System.out.println("Num of transfer Rules loaded: "
					+ aTransferRuleSetList.length);
			translationOut.println("\r\nTransfer Rules loaded: ");

			for (int i = 0; i < aTransferRuleSetList.length; i++) {
				System.out.println("TransferRuleSet no. " + i);
				translationOut.println("TransferRuleSet no. " + i);
				for (int j = 0; j < aTransferRuleSetList[i].size(); j++) {
					// (
					// aTransferRuleSetList[i].elementAt(j)).printTransferRuleSimple();
				}
			}

			System.out
					.println("max comp ="
							+ vParseProductions.elementAt(vParseProductions
									.size() - 1));

			// English to Filipino
			if (cLang == '1') {
				for (int i = 0; i < aTransferRuleSetList.length; i++) {

					// To count the number of parse productions that have
					// a matching transfer rule in rule set
					int countApp = 0;

					for (int k = 0; k < vParseProductions.size(); k++) {
						boolean matchFound = false;
						for (int j = 0; j < aTransferRuleSetList[i].size() && !matchFound; j++) {

							if (vParseProductions.elementAt(k).equals(
									aTransferRuleSetList[i].elementAt(j).engSide)) {
								countApp++;
								matchFound = true;
							}
						}
					}
					if(countApp == vParseProductions.size())
						applicableRuleSets.add(aTransferRuleSetList[i]);
				}
			}
			// Filipino to English
			else {
				for (int i = 0; i < aTransferRuleSetList.length; i++) {

					//System.out.println("Checking rule set ");
					//(aTransferRuleSetList[i]).elementAt(aTransferRuleSetList[i].size()-1).printTransferRuleSimple();
					int countApp = 0;

					for (int k = 0; k < vParseProductions.size(); k++) {
						boolean matchFound = false;
						for (int j = 0; j < aTransferRuleSetList[i].size() && !matchFound; j++) {

							if (vParseProductions.elementAt(k).equals(
									aTransferRuleSetList[i].elementAt(j).filSide)) {
								countApp++;
								matchFound = true;
							}
						}
					}
					if(countApp == vParseProductions.size())
						applicableRuleSets.add(aTransferRuleSetList[i]);
				}
			}

			System.out.println("# of Applicable rule sets " + applicableRuleSets.size());

			for(int i=0; i < applicableRuleSets.size(); i++) {

				FStructure rootSource = fsInput[0];
				FStructure currSoruce = rootSource;
				FStructure rootTarget;
				FStructure currTarget;

				System.out.println("initial production= " + rootSource.name + " : "
						+ getChildren(rootSource));
				TransferRule tr = searchMatchingTransferRule((Vector)applicableRuleSets.elementAt(i),
						rootSource.name + " : " + getChildren(rootSource), cLang);

				String ruleSetID = ((TransferRule)((Vector)applicableRuleSets.elementAt(i)).elementAt(0)).ruleSet;
				System.out.println("Using ruleSet #" + ruleSetID);

				if (cLang == '1') {
					rootTarget = new FStructure(tr.leftHandSideFil);
				} else {
					rootTarget = new FStructure(tr.leftHandSideEng);
				}

				expandTargetStructureRecursive((Vector)applicableRuleSets.elementAt(i), rootSource,
						rootTarget, cLang);

				correctFStruct(rootTarget, rootTarget, cLang);

				replaceSourceWordsWithTarget(rootTarget, cLang);

				translationOut.println("\r\nTarget tree: ");
				printFStructureContentsRecursive(rootTarget, "\t");
				printFStructureContentsRecursive(rootTarget, "\t", translationOut);

				String output = realizeSentence(rootTarget, cLang);
				System.out.println(output);
				translationOut.println("Rule-based output: " + output);
			}
		}

		catch (Exception e) {
			exceptionRBE = true;

			System.out.print("Problem translating sentence." + e.getMessage());
			e.printStackTrace();
		}

		exceptionRBE = true;
		if (failAnalysis || exceptionRBE) {
			if (failAnalysis)
				translationOut
						.println("\r\nError Analyzing Input Sentence using RBE");

			if (applicableRuleSets.size() == 0)
				translationOut
						.println("\r\nError: No candidate rule available");
			// dbConnector.connect();
			boolean bEnglish = false;
			char cTarget = 'f';
			if (cLang == '1') {
				bEnglish = true;
				cTarget = 'e';
			}
			text.translation.Translator textTranslator = new text.translation.Translator(
					bEnglish);

			InputAnalyzer ia = new InputAnalyzer();
			Vector vSentences = ia.analyzeTranslateInput(inputSentence,
					cTarget, "Regular Expression");
			String strTranslation = textTranslator.translate(vSentences);

			// outWriter.println(strTranslation);
			if (strTranslation != null)
				translationOut.println("\r\nExample-based translation is : "
						+ strTranslation);
			else
				translationOut
						.println("\r\nNo translation using example base ");

			// text.ia.SentenceDetector sentenceDetector = new
			// text.ia.SentenceDetector();
			// textTranslator.translate(sentenceDetector.toSentences(inputSentence,
			// "Regular Expression", cTarget));
		}

		// close the log files
		// outWriter.close();
		writer.close();
		translationOut.close();
	}
}
